"""
RSI分析器 - 统计虚拟货币RSI低于30的数据并进行可视化标注
"""

import pandas as pd
import numpy as np
import matplotlib
matplotlib.use('Agg')  # 使用非交互式后端，不显示GUI窗口
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from datetime import datetime, timedelta
import logging
from typing import List, Tuple, Optional
import warnings
warnings.filterwarnings('ignore')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class RSIAnalyzer:
    """RSI分析器类"""
    
    def __init__(self, rsi_period: int = 14, oversold_threshold: float = 30.0):
        """
        初始化RSI分析器
        
        Args:
            rsi_period: RSI计算周期，默认14
            oversold_threshold: 超卖阈值，默认30
        """
        self.rsi_period = rsi_period
        self.oversold_threshold = oversold_threshold
    
    def calculate_rsi(self, prices: pd.Series) -> pd.Series:
        """
        计算RSI指标
        
        Args:
            prices: 价格序列（通常为收盘价）
            
        Returns:
            RSI值序列
        """
        delta = prices.diff()
        gain = (delta.where(delta > 0, 0)).rolling(window=self.rsi_period).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(window=self.rsi_period).mean()
        
        rs = gain / loss
        rsi = 100 - (100 / (1 + rs))
        
        return rsi
    
    def find_oversold_signals(self, data: pd.DataFrame) -> pd.DataFrame:
        """
        找到RSI从超卖区域反弹的信号点
        即：当前RSI ≥ 阈值，且上一个时间点RSI < 阈值的点
        
        Args:
            data: 包含价格和RSI数据的DataFrame
            
        Returns:
            超卖反弹信号点的DataFrame
        """
        if 'rsi' not in data.columns:
            raise ValueError("数据中缺少RSI列")
        
        # 创建前一期RSI列
        data_copy = data.copy()
        data_copy['prev_rsi'] = data_copy['rsi'].shift(1)
        
        # 找到RSI从超卖区域反弹的点
        # 条件：当前RSI >= 阈值 且 前一期RSI < 阈值
        bounce_mask = (data_copy['rsi'] >= self.oversold_threshold) & (data_copy['prev_rsi'] < self.oversold_threshold)
        oversold_signals = data_copy[bounce_mask].copy()
        
        # 添加信号标记
        oversold_signals['signal_type'] = 'oversold_bounce'
        oversold_signals['signal_strength'] = oversold_signals['rsi'] - oversold_signals['prev_rsi']  # 反弹幅度
        oversold_signals['prev_rsi_value'] = oversold_signals['prev_rsi']  # 保存前一期RSI值
        
        return oversold_signals
    
    def analyze_oversold_patterns(self, oversold_signals: pd.DataFrame) -> dict:
        """
        分析超卖反弹模式的统计信息
        
        Args:
            oversold_signals: 超卖反弹信号点DataFrame
            
        Returns:
            统计信息字典
        """
        if oversold_signals.empty:
            return {
                'total_signals': 0,
                'avg_rsi_value': 0,
                'min_rsi_value': 0,
                'max_rsi_value': 0,
                'avg_prev_rsi': 0,
                'avg_bounce_strength': 0,
                'signal_dates': []
            }
        
        stats = {
            'total_signals': len(oversold_signals),
            'avg_rsi_value': oversold_signals['rsi'].mean(),  # 反弹后的平均RSI
            'min_rsi_value': oversold_signals['rsi'].min(),
            'max_rsi_value': oversold_signals['rsi'].max(),
            'avg_prev_rsi': oversold_signals['prev_rsi_value'].mean(),  # 反弹前的平均RSI
            'min_prev_rsi': oversold_signals['prev_rsi_value'].min(),
            'avg_bounce_strength': oversold_signals['signal_strength'].mean(),  # 平均反弹幅度
            'signal_dates': oversold_signals.index.tolist()
        }
        
        return stats
    
    def create_visualization(self, 
                           data: pd.DataFrame, 
                           oversold_signals: pd.DataFrame,
                           symbol: str,
                           save_path: Optional[str] = None) -> None:
        """
        创建价格和RSI的可视化图表，标注超卖信号
        
        Args:
            data: 完整的价格和RSI数据
            oversold_signals: 超卖信号点
            symbol: 交易对符号
            save_path: 图表保存路径（可选）
        """
        fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 10), sharex=True)
        
        # 第一个子图：价格走势
        ax1.plot(data.index, data['close'], label='收盘价', color='blue', linewidth=1.5)
        
        # 标注超卖反弹信号点
        if not oversold_signals.empty:
            ax1.scatter(oversold_signals.index, oversold_signals['close'], 
                       color='green', s=100, marker='^', label=f'RSI反弹信号', zorder=5)
            
            # 添加文本标注
            for idx, row in oversold_signals.iterrows():
                ax1.annotate(f'RSI:{row["prev_rsi_value"]:.1f}→{row["rsi"]:.1f}', 
                           xy=(idx, row['close']), 
                           xytext=(10, 10), textcoords='offset points',
                           bbox=dict(boxstyle='round,pad=0.3', facecolor='lightgreen', alpha=0.7),
                           arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0'),
                           fontsize=8)
        
        ax1.set_title(f'{symbol} 价格走势与RSI反弹信号', fontsize=16, fontweight='bold')
        ax1.set_ylabel('价格 (USDT)', fontsize=12)
        ax1.legend()
        ax1.grid(True, alpha=0.3)
        
        # 第二个子图：RSI指标
        ax2.plot(data.index, data['rsi'], label='RSI', color='purple', linewidth=1.5)
        ax2.axhline(y=self.oversold_threshold, color='red', linestyle='--', 
                   label=f'超卖线 ({self.oversold_threshold})', alpha=0.7)
        ax2.axhline(y=70, color='green', linestyle='--', 
                   label='超买线 (70)', alpha=0.7)
        
        # 填充超卖区域
        ax2.fill_between(data.index, 0, self.oversold_threshold, 
                        alpha=0.2, color='red', label='超卖区域')
        
        # 标注超卖反弹信号点
        if not oversold_signals.empty:
            ax2.scatter(oversold_signals.index, oversold_signals['rsi'], 
                       color='green', s=100, marker='^', zorder=5)
        
        ax2.set_title('RSI指标', fontsize=14)
        ax2.set_ylabel('RSI值', fontsize=12)
        ax2.set_xlabel('时间', fontsize=12)
        ax2.set_ylim(0, 100)
        ax2.legend()
        ax2.grid(True, alpha=0.3)
        
        # 格式化x轴 - 更详细的时间坐标
        # 根据数据时间跨度选择合适的时间格式和间隔
        time_span_hours = (data.index[-1] - data.index[0]).total_seconds() / 3600
        
        if time_span_hours <= 48:  # 2天内，每4小时一个刻度
            ax2.xaxis.set_major_locator(mdates.HourLocator(interval=4))
            ax2.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d %H:%M'))
            ax2.xaxis.set_minor_locator(mdates.HourLocator(interval=1))
        elif time_span_hours <= 168:  # 7天内，每天一个刻度
            ax2.xaxis.set_major_locator(mdates.DayLocator(interval=1))
            ax2.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
            ax2.xaxis.set_minor_locator(mdates.HourLocator(interval=6))
        elif time_span_hours <= 720:  # 30天内，每天一个刻度
            ax2.xaxis.set_major_locator(mdates.DayLocator(interval=1))
            ax2.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
            ax2.xaxis.set_minor_locator(mdates.HourLocator(interval=12))
        else:  # 超过30天，每3天一个刻度
            ax2.xaxis.set_major_locator(mdates.DayLocator(interval=3))
            ax2.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d'))
            ax2.xaxis.set_minor_locator(mdates.DayLocator(interval=1))
        
        # 设置刻度样式
        ax2.tick_params(axis='x', which='major', labelsize=10, rotation=45)
        ax2.tick_params(axis='x', which='minor', length=4)
        ax2.grid(True, which='minor', alpha=0.2, linestyle=':')
        ax2.grid(True, which='major', alpha=0.3)
        
        plt.tight_layout()
        
        if save_path:
            plt.savefig(save_path, dpi=300, bbox_inches='tight')
            logger.info(f"图表已保存到: {save_path}")
        
        plt.show()
    
    def generate_report(self, 
                       symbol: str, 
                       stats: dict, 
                       period_days: int) -> str:
        """
        生成分析报告
        
        Args:
            symbol: 交易对符号
            stats: 统计信息
            period_days: 分析周期天数
            
        Returns:
            报告字符串
        """
        report = f"""
==================== RSI超卖反弹分析报告 ====================
交易对: {symbol}
分析周期: {period_days} 天
RSI周期: {self.rsi_period}
超卖阈值: {self.oversold_threshold}

================= 统计结果 =================
反弹信号总数: {stats['total_signals']}
反弹后平均RSI: {stats['avg_rsi_value']:.2f}
反弹前平均RSI: {stats.get('avg_prev_rsi', 0):.2f}
最低反弹前RSI: {stats.get('min_prev_rsi', 0):.2f}
平均反弹幅度: {stats.get('avg_bounce_strength', 0):.2f}

================= 信号详情 =================
"""
        
        if stats['total_signals'] > 0:
            report += "RSI反弹信号出现时间:\n"
            for i, date in enumerate(stats['signal_dates'][:10]):  # 只显示前10个
                report += f"{i+1}. {date.strftime('%Y-%m-%d %H:%M:%S')}\n"
            
            if len(stats['signal_dates']) > 10:
                report += f"... 还有 {len(stats['signal_dates']) - 10} 个信号\n"
        else:
            report += "在分析周期内未发现RSI超卖反弹信号。\n"
        
        report += "=" * 50
        
        return report
    
    def analyze_symbol(self, 
                      data: pd.DataFrame, 
                      symbol: str,
                      period_days: int = 30,
                      save_chart: bool = True) -> dict:
        """
        分析单个交易对的RSI超卖情况
        
        Args:
            data: 价格数据DataFrame，需包含'close'列
            symbol: 交易对符号
            period_days: 分析周期天数
            save_chart: 是否保存图表
            
        Returns:
            分析结果字典
        """
        logger.info(f"开始分析 {symbol} 的RSI超卖反弹情况...")
        
        # 计算RSI
        data['rsi'] = self.calculate_rsi(data['close'])
        
        # 找到超卖反弹信号
        oversold_signals = self.find_oversold_signals(data)
        
        # 统计分析
        stats = self.analyze_oversold_patterns(oversold_signals)
        
        # 生成报告
        report = self.generate_report(symbol, stats, period_days)
        
        # 创建可视化
        save_path = f"{symbol}_rsi_analysis.png" if save_chart else None
        self.create_visualization(data, oversold_signals, symbol, save_path)
        
        # 打印报告
        print(report)
        
        return {
            'symbol': symbol,
            'stats': stats,
            'oversold_signals': oversold_signals,
            'report': report,
            'data_with_rsi': data
        }
